import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
import matplotlib as mpl
from sklearn.metrics import mean_squared_error, mean_absolute_error
# 读取数据
train2024 = pd.read_csv('dalian_weather_2024.csv', encoding='utf-8')
features2023 = pd.read_csv('dalian_weather_2023.csv', encoding='utf-8')
# 合并数据
combined_data = pd.concat([features2023, train2024], ignore_index=True)
#截取日期的月份去掉星期几和几号
combined_data['日期'] = combined_data['日期'].apply(lambda x: x[0:10])
# 使用 loc 方法更新最高气温和最低气温
for col in ['最高气温', '最低气温']:
    combined_data[col] = combined_data[col].str.replace('℃', '').str.strip().astype(int)
#拆分日期
combined_data['日期'] = combined_data['日期'].apply(lambda x: x[0:10])
combined_data['日期'] = pd.to_datetime(combined_data['日期'])
combined_data['年'] = combined_data['日期'].dt.year
combined_data['月'] = combined_data['日期'].dt.month
combined_data['日'] = combined_data['日期'].dt.day
combined_data['星期'] = combined_data['日期'].dt.weekday
# 创建一个映射字典
day_map = {
    1: 'Mon',
    2: 'Tue',
    3: 'Wed',
    4: 'Thu',
    5: 'Fri',
    6: 'Sat',
    0: 'Sun'
}

# 使用映射字典将完整的星期名称转换为缩写
combined_data['星期'] = combined_data['星期'].map(day_map)

#删除列
combined_data.drop(['日期'], axis=1, inplace=True)


# 增加avg列给机器学习用
combined_data = combined_data.assign(平均气温=(combined_data['最高气温'] + combined_data['最低气温']) / 2)
#调整未知把气温放到日期后面
combined_data = combined_data[['年', '月', '日', '星期', '最高气温', '最低气温']]


#转换为干净数据

combined_data.to_csv('clean_data.csv', index=False)


#One-Hot Encoding热编码全部转化为数值数据
combined_data = pd.get_dummies(combined_data)
X = combined_data.drop(columns=['最高气温', '最低气温'],axis=1)
y = combined_data[['最高气温', '最低气温']]
train_X, test_X, train_y, test_y = train_test_split(X, y, test_size=0.25, random_state=42)
print('训练集特征样式：', train_X.shape)
print('测试集特征样式：', test_X.shape)
print('训练集标签样式：', train_y.shape)
print('测试集标签样式：', test_y.shape)

#建模
model = RandomForestRegressor(n_estimators=1000, random_state=42)
model.fit(train_X, train_y)

# 预测结果
predictions = model.predict(test_X)
# 计算均方根误差
mse = mean_squared_error(test_y, predictions)
# 计算均方根误差
rmse = np.sqrt(mse)
# 计算平均绝对误差
mae = mean_absolute_error(test_y, predictions)
#以上误差均数值越小性能预估越准
print('MSE:', mse)
print('RMSE关注较大的误差:', rmse)
print('MAE:', mae)


# 得到特征重要性
importances = list(model.feature_importances_)
feature_importances = [(feature, round(importance, 2)) for feature, importance in zip(train_X.columns, importances)]
feature_importances = sorted(feature_importances, key=lambda x: x[1], reverse=True)
[print('Variable: {:20} Importance: {}'.format(*pair)) for pair in feature_importances]




dates = pd.date_range(start='2023-01-01', end='2024-12-31')

future_data = pd.DataFrame({
    '年': dates.year,
    '月': dates.month,
    '日': dates.day,
    '星期': dates.day_name()
})
future_data['星期'] = future_data['星期'].apply(lambda x: x[0:3])

# print(future_data.head(5))
# One-Hot Encoding
future_data = pd.get_dummies(future_data)

# 确保未来的特征与训练特征一致
missing_cols = set(train_X.columns) - set(future_data.columns)
for c in missing_cols:
    future_data[c] = 0
future_data = future_data[train_X.columns]

# 查看数据
# print(future_data.head(5))

# 预测结果
future_predictions = model.predict(future_data)
future_df = pd.DataFrame(future_predictions, columns=['预测最高气温', '预测最低气温'])
future_df['日期'] = pd.date_range(start='2023-01-01', periods=len(future_df), freq='D')
future_df = future_df[['日期', '预测最高气温', '预测最低气温']]

# 查看预测结果
print(future_df)
#画出2023年-2024年预测最高最低温度图
plt.figure(figsize=(10, 6))

# 将年、月、日列组合成日期字符串
combined_data['日期'] = pd.to_datetime(combined_data.apply(
    lambda row: f"{row['年']}-{row['月']:02d}-{row['日']:02d}", axis=1
))
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.plot(combined_data['日期'], combined_data['最高气温'], label='实际最高温度')
plt.plot(combined_data['日期'], combined_data['最低气温'], label='实际最低温度')
plt.plot(future_df['日期'], future_df['预测最高气温'], label='预测最高温度')
plt.plot(future_df['日期'], future_df['预测最低气温'], label='预测最低温度')
plt.xlabel('日期')
plt.ylabel('温度(°C)')
plt.title('2023-2024年的天气最高最低气温预报')
plt.legend()
#保存图片
plt.savefig('weather_predictions2023-2024.png')
#显示图片
plt.show()
#存储预测天气温度csv
future_df.to_csv('future_weather_predictions2023-2024.csv', index=False)

